from urllib.parse import urlparse, parse_qs, parse_qsl
import re


def parse_url(url: str) -> dict:
    """
    解析 URL 并返回所有关键信息，包括：
    - 协议 (scheme)
    - 主机名 (hostname，不含端口)
    - 端口 (port，自动填充默认值)
    - 网络位置 (netloc，含端口)
    - 路径 (path)
    - 参数 (params)
    - 查询字符串 (query)
    - 锚点 (fragment)
    - 完整原始 URL (url)
    - 是否安全协议 (is_secure)
    - 是否显式指定端口 (explicit_port)
    - parsed_query: 解析后的查询参数字典（支持多值）
    - parsed_query_list: 解析后的查询参数列表（保留原始顺序）
    支持：HTTP/HTTPS/WebSocket/IPv6 等协议
    """

    parsed = urlparse(url)
    netloc = parsed.netloc

    # ----------------------------- 解析主机名和端口 -----------------------------
    hostname, port = None, None

    # 处理 IPv6 地址（如 [::1]:8080）
    if netloc.startswith('['):
        match = re.match(r'^$$([^$$]+)\](?::(\d+))?$', netloc)
        if match:
            hostname, port = match.group(1), match.group(2)
    else:
        # 普通主机名（如 example.com:8080）
        if ':' in netloc:
            hostname, port = netloc.split(':', 1)
        else:
            hostname = netloc

    # 若未解析出主机名，回退到 netloc（兼容无端口的情况）
    hostname = hostname or netloc

    # ----------------------------- 处理端口 -----------------------------
    explicit_port = bool(port)  # 是否显式指定了端口
    try:
        port = int(port) if port else None
    except ValueError:
        port = None  # 非数字端口视为无效

    # 根据协议填充默认端口
    default_ports = {'http': 80, 'https': 443, 'ws': 80, 'wss': 443}
    if not port and parsed.scheme in default_ports:
        port = default_ports[parsed.scheme]

    # ----------------------------- 构建返回结果 -----------------------------
    return {
        "url": url,  # 原始 URL
        "scheme": parsed.scheme,  # 协议
        "hostname": hostname,  # 主机名（不含端口）
        "port": port,  # 端口（自动填充默认值）
        "netloc": f"{hostname}:{port}" if (port and explicit_port) else hostname,  # 完整网络位置
        "path": parsed.path or "/",  # 路径（默认 /）
        "params": parsed.params,  # 参数
        "query": parsed.query,  # 查询字符串
        "fragment": parsed.fragment,  # 锚点
        "is_secure": parsed.scheme in ('https', 'wss'),  # 是否安全协议
        "explicit_port": explicit_port,  # 是否显式指定端口
        "parsed_query": parse_qs(parsed.query),  # 字典形式，值类型为列表
        "parsed_query_list": parse_qsl(parsed.query),  # 列表形式，保留原始顺序
    }


if __name__ == '__main__':
    print(parse_url("http://example.com:8080/path?query=1&id=1#frag"))
